import re

from PySide6.QtCore import Signal, Slot, Qt, QSize
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QPushButton


class KeyButton(QPushButton):
  pressed = Signal(int, str)
  def __init__(self, modes=None, parent=None):
    super().__init__(parent)
    self.modes = modes or []
    self.setFocusPolicy(Qt.NoFocus)
    self.setAutoRepeat(True)
    self.m_modes = []
    self.setStyleSheet('''
        QPushButton {
            background-color: #32373a;
            border-radius: 5px;
            margin: 5px;
            font-size: 26px;
            color: #e8e8e8;
        }
        QPushButton:hover {
           background-color: #b5b6b7;
        }
    ''')
    for mode in modes:
      if mode.type == Type.Auto:
        mode.type = self.find(mode.value)
      if mode.display is None:
        mode.display = mode.value
      self.m_modes.append(mode)

    if len(modes) > 0:
      self.m_preMode = self.m_mode = self.m_modes[0]
      self.setDisplayContent(self.m_mode.display)

    self.clicked.connect(self.onPressed)


  def find(self, value: str):
    if re.fullmatch(r"[a-z]", value):
      return Type.LowerCase
    elif re.fullmatch(r"[A-Z]", value):
      return Type.UpperCase
    else:
      return Type.SpecialChar

  def find_mode(self, type: int):
    for mode in self.m_modes:
      if mode.type == type:
        return mode
    return self.m_modes[0]

  def findNext(self):
    index = self.modes.index(self.m_mode)
    next_index = (index + 1) % len(self.modes)
    return self.modes[next_index]

  def setDisplayContent(self, content):
    if isinstance(content, str):
      self.setText(content)
    elif isinstance(content, QIcon):
      self.setIcon(content)
      self.setIconSize(QSize(1.2 * self.width(), 1.2 * self.height()))

  def switchCapsLock(self):
    if self.m_mode.type == Type.SpecialChar:
      return
    self.m_preMode = self.m_mode
    self.m_mode = self.find_mode(
      Type.UpperCase if self.m_mode.type == Type.LowerCase else Type.LowerCase)
    self.setDisplayContent(self.m_mode.display)

  def switchSpecialChar(self):
    if self.m_mode.type == Type.SpecialChar:
      self.m_mode = self.m_preMode
    else:
      self.m_preMode = self.m_mode
      self.m_mode = self.find_mode(Type.SpecialChar)
    self.setDisplayContent(self.m_mode.display)

  def switching(self):
    self.m_mode = self.findNext()
    print(self.m_mode.display)
    self.setDisplayContent(self.m_mode.display)

  def mode(self):
    return self.m_mode

  def onReponse(self, receiverObj, receiver):
    self.pressed.connect(receiver)

  @Slot()
  def onPressed(self):
    self.pressed.emit(self.m_mode.key, self.m_mode.value)

class Type:
  Auto = 0
  LowerCase = 1
  UpperCase = 2
  SpecialChar = 3

class Mode:
  def __init__(self, key, value, display=None, type=None):
    if type is None:
      type = Type.Auto
    self.key = key
    self.value = value
    self.display = display or value
    self.type = type
